Imports BitSmoke.Core.Storage
Imports BitSmoke.Core.Net.Connection
Imports BitSmoke.Core.Net.Messages
Imports BitSmoke.Core.Data.Profiles
Imports BitSmoke.Core.Data.Preferences

Imports System.Net
Imports System.Net.Sockets

Namespace Core.Data
    Public Class DataRoot
        Implements IDisposable

#Region " Shared "
        Private Shared zData As DataRoot

        Public Shared Function getDataRoot() As DataRoot
            If zData Is Nothing Then
                zData = New DataRoot
                Store.load(zData)
            End If

            Return zData
        End Function
#End Region

#Region " Private Properties "
        Private zPrefs As MyPreferences
        Private zMyProfile As MyProfile
        Private zUserProfilesByGUID As New Dictionary(Of Guid, UserProfile)
        Private zUserProfilesByIPEndPoint As New Dictionary(Of IPEndPoint, UserProfile)
        Private zMessageTypesByID As New Dictionary(Of Byte, Type)
#End Region

#Region " Public Properties "
        Public Property Preferences() As MyPreferences
            Get
                Return zPrefs
            End Get
            Friend Set(ByVal value As MyPreferences)
                zPrefs = value
            End Set
        End Property

        Public Property MyProfile() As MyProfile
            Get
                Return zMyProfile
            End Get
            Friend Set(ByVal value As MyProfile)
                zMyProfile = value
            End Set
        End Property

        Friend ReadOnly Property UserProfilesByGUID() As Dictionary(Of Guid, UserProfile)
            Get
                Return zUserProfilesByGUID
            End Get
        End Property
#End Region

#Region " Events "
        Public Event NewUser(ByVal pUP As UserProfile)
#End Region

#Region " Constructors "
        Public Sub New()
            'cache messages by id so when we look up the message it's instant
            Dim tMsg As Type
            Dim bID As Byte
            For Each tMsg In Reflection.Assembly.GetExecutingAssembly.GetTypes
                If tMsg.IsClass AndAlso tMsg.BaseType Is GetType(Message) Then
                    bID = CType(tMsg.GetField("ID").GetValue(Nothing), Byte)

                    zMessageTypesByID.Add(bID, tMsg)
                End If
            Next
        End Sub
#End Region

#Region " Public Methods "
        Public Function getMessageType(ByVal pB_ID As Byte) As Type
            If zMessageTypesByID.ContainsKey(pB_ID) Then
                Return zMessageTypesByID(pB_ID)
            Else
                Return Nothing
            End If
        End Function

        Public Sub createUserProfile(ByVal pGUID As Guid, ByVal pIP As IPAddress, ByVal pI_CommunicationPort As UInt16, ByVal pB_ProtocolVersion As Byte)
            Dim up As UserProfile

            If zUserProfilesByGUID.ContainsKey(pGUID) Then
                'Debug.WriteLine("EXISTING " & pIP.ToString & ":" & pI_CommunicationPort & " - " & pGUID.ToString)

                up = zUserProfilesByGUID(pGUID)
                up.update(pIP, pI_CommunicationPort, pB_ProtocolVersion)
            Else
                Debug.WriteLine("NEW " & pIP.ToString & ":" & pI_CommunicationPort & " - " & pGUID.ToString)

                up = New UserProfile(pGUID, pIP, pI_CommunicationPort, pB_ProtocolVersion)

                zUserProfilesByGUID.Add(up.GUID, up)

                RaiseEvent NewUser(up)
            End If
        End Sub

        Public Sub acceptConnection(ByVal pIPEP As IPEndPoint, ByVal pTCP As TcpClient)
            Dim user As UserProfile = Nothing

            If zUserProfilesByIPEndPoint.ContainsKey(pIPEP) Then
                user = zUserProfilesByIPEndPoint(pIPEP)

                If (Not user.Blacklisted) AndAlso (user.ProtocolVersion = DataConnection.ProtocolVersion) AndAlso (user.Connection.State = ConnectionStateConstants.ConnectionState_Disconnected) Then
                    user.acceptConnection(pTCP)
                End If
            End If
        End Sub
#End Region

#Region " IDisposable Support "
        Private disposedValue As Boolean = False        ' To detect redundant calls

        ' IDisposable
        Protected Overridable Sub Dispose(ByVal disposing As Boolean)
            If Not Me.disposedValue Then
                If disposing Then
                    ' free managed resources when explicitly called
                    Dim kvp As KeyValuePair(Of Guid, UserProfile)
                    For Each kvp In zUserProfilesByGUID
                        kvp.Value.Dispose()
                    Next
                End If

                ' free shared unmanaged resources
            End If
            Me.disposedValue = True
        End Sub

        ' This code added by Visual Basic to correctly implement the disposable pattern.
        Public Sub Dispose() Implements IDisposable.Dispose
            ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
            Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub
#End Region

    End Class
End Namespace